home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 May / EnigmA AMIGA RUN 18 (1997)(G.R. Edizioni)(IT)[!][issue 1997-05][EAR-CD II].iso / earcd / comm / misc / new8n1.lha / 8n1_000.s next >
Text File  |  1997-02-18  |  61KB  |  2,011 lines

  1. ********************************************************************************
  2. **                                          **
  3. **  Name       : 8n1_000.s                              **
  4. **  Copyright  : © Copyright 96-97                          **
  5. **  Author     : Iain Barclay                              **
  6. **  Created    : 18 Feb 97                              **
  7. **  Version    : 37.31                                  **
  8. **                                          **
  9. ********************************************************************************
  10.      ;
  11.      ;      SNMA specific options
  12.      ;
  13.      IFD      SNMA
  14.      ;
  15.      CPU      M68010
  16.      ;
  17.      SNMAOPT  Q,A,M,T,E-
  18.      ;
  19.      ELSE
  20.      IFD PHXASS
  21.      machine 68010
  22.      OPT !
  23.      ENDC
  24.      ENDC
  25.      ;
  26.      ;
  27. DEBUG     SET    0
  28. NEWCODE  SET    1
  29. SETDSR     SET    0
  30. NCOMM     SET    0
  31.      ;
  32.      ;
  33.      ;
  34.      SECTION  text,CODE
  35.      ;
  36.      ;
  37.      ;
  38. DEVICES_SERIAL_I_OBSOLETE  EQU        1
  39.      ;
  40.      ;
  41.      ;
  42.      INCLUDE  "exec/lists.i"
  43.      INCLUDE  "exec/memory.i"
  44.      INCLUDE  "exec/resident.i"
  45.      INCLUDE  "exec/devices.i"
  46.      INCLUDE  "exec/execbase.i"
  47.      INCLUDE  "exec/io.i"
  48.      INCLUDE  "exec/ports.i"
  49.      INCLUDE  "exec/errors.i"
  50.      INCLUDE  "exec/initializers.i"
  51.      INCLUDE  "intuition/preferences.i"
  52.      INCLUDE  "devices/timer.i"
  53.      INCLUDE  "devices/serial.i"
  54.      INCLUDE  "hardware/custom.i"
  55.      INCLUDE  "hardware/cia.i"
  56.      INCLUDE  "hardware/intbits.i"
  57.      INCLUDE  "hardware/adkbits.i"
  58.      INCLUDE  "resources/misc.i"
  59.      INCLUDE  "exec/alerts.i"
  60.      INCLUDE  "exec/macros.i"
  61.      INCLUDE  "8n1.device_rev.i"
  62.      ;
  63.      ;      Define hardware references
  64.      ;
  65.      XREF      _custom
  66.      XREF      _intena,_intenar,_intreq,_intreqr
  67.      XREF      _ciab,_ciabpra
  68.      XREF      _serper,_serdat,_serdatr
  69.      XREF      _adkcon,_adkconr
  70.      ;
  71.      ;      Exec Functions
  72.      ;
  73.      XREF      _LVORemDevice,_LVOOpenDevice,_LVOCloseDevice
  74.      XREF      _LVOSupervisor
  75.      XREF      _LVOAllocMem,_LVOFreeMem,_LVOCopyMem
  76.      XREF      _LVOReplyMsg
  77.      XREF      _LVOSendIO,_LVOAbortIO
  78.      XREF      _LVODisable,_LVOEnable
  79.      XREF      _LVOFindName
  80.      XREF      _LVOOpenResource
  81.      XREF      _LVOAddIntServer,_LVORemIntServer
  82.      XREF      _LVOSetIntVector
  83.      XREF      _LVOAlert
  84.      XREF      _LVOOpenLibrary,_LVOCloseLibrary
  85.      ;
  86.      ;      Misc Resource Functions
  87.      ;
  88.      XREF      _LVOAllocMiscResource,_LVOFreeMiscResource
  89.      ;
  90.      ;      Intuition Functions
  91.      ;
  92.      XREF      _LVOGetPrefs
  93.      ;
  94.      ;      Mask used to get rid of the printer bits.
  95.      ;
  96. PRTMASK  EQU      (CIAF_PRTRPOUT|CIAF_PRTRBUSY)
  97.      ;
  98.      ;      Autovector offsets
  99.      ;
  100. LVL1VEC  EQU      (1-1)*4+$64
  101. LVL5VEC  EQU      (5-1)*4+$64
  102.      ;
  103.      ;  New Style device stuff (not the best way but it will do for now)
  104.      ;  if u do not have new Stlye stuff defined elsewhere remove these ;
  105. ;NSCMD_DEVICEQUERY   EQU $4000
  106. ; STRUCTURE NSDEVICEQUERYRESULT,0
  107. ;    ULONG   DEVQUERYFORMAT
  108. ;    ULONG   SIZEAVAILABLE
  109. ;    UWORD   DEVICETYPE
  110. ;    UWORD   DEVICESUBTYPE
  111. ;    APTR    SUPPORTEDCOMMANDS
  112. ;    LABEL   NSDEVICEQUERYRESULT_SIZE
  113. ;NSDEVTYPE_SERIAL    EQU 11
  114.      ;
  115.      ;      Device base
  116.      ;
  117.      STRUCTURE Base8n1,LIB_SIZE
  118.      UBYTE      vb_SaveDDRA
  119.      UBYTE      vb_SavePRA
  120.      APTR      vb_MiscBase
  121.      APTR      vb_OldLevel1
  122.      APTR      vb_OldLevel5
  123.      ULONG      vb_SegList
  124.      ULONG      vb_DefBaud
  125.      ULONG      vb_DefRBufLen
  126.      ULONG      vb_CurRBuf
  127.      ULONG      vb_CurRBufLen
  128.      ULONG      vb_CurBaud
  129.      UBYTE      vb_SerFlags
  130.      UBYTE      vb_Initialized
  131.      LABEL      sizeof_Base8n1
  132.      ;
  133.      ;
  134.      ;
  135. DISABLE  MACRO
  136.      IFNC      '\1',''
  137.      move.w   #INTF_\1,_intena
  138.      ELSE
  139.      jsr      _LVODisable(a6)
  140.      ENDC
  141.      ENDM
  142.      ;
  143. ENABLE     MACRO
  144.      IFNC      '\1',''
  145.      move.w   #INTF_SETCLR|INTF_\1,_intena
  146.      ELSE
  147.      jsr      _LVOEnable(a6)
  148.      ENDC
  149.      ENDM
  150.      ;
  151.      ;
  152.      ;
  153.     IFNE DEBUG
  154.      XREF      DPutFmt
  155.      XREF      _SendText
  156.     ENDC
  157. PUTDEBUG macro      ;[msg]
  158.      ifge      DEBUG-2
  159.      movem.l  d0/d1/a0/a1,-(sp)
  160.      lea      (.msg\@,pc),a0  ;Point to static format string
  161.      lea      (4*4,sp),a1      ;Point to args
  162.      bsr      DPutFmt
  163.      movem.l  (sp)+,d0/d1/a0/a1
  164.      bra.b      .end\@
  165.  
  166. .msg\@     dc.b      \1,10,0
  167.      CNUL      0,4
  168. .end\@
  169.      endc
  170.      endm
  171.      ;
  172.      ;
  173.      ;
  174. DEBUG1     MACRO
  175.      IFNE       DEBUG
  176.      move.l   \2,-(sp)
  177.      pea.l      debug1s\@$
  178.      pea.l      Name
  179.      jsr      _SendText(pc)
  180.      lea.l      12(sp),sp
  181.      bra.b      debug1x\@$
  182. debug1s\@$:
  183.      dc.b      \1,0
  184.      CNOP      0,2
  185. debug1x\@$:
  186.      ENDC
  187.      ENDM
  188. DEBUG0     MACRO
  189.      pea.l      debug1s\@$
  190.      pea.l      Name
  191.      jsr      _SendText(pc)
  192.      addq      #8,sp
  193.      bra.b      debug1x\@$
  194. debug1s\@$:
  195.      dc.b      \1,0
  196. debug1x\@$:
  197.      ENDM
  198.  
  199. DEBUGIO  MACRO
  200.      IFNE      DEBUG
  201.      lea.l      \1,a0
  202.      jsr      printIO
  203.      ENDC
  204.      ENDM
  205.      ;
  206.      ;
  207.      ;
  208. Start:
  209.      moveq      #-1,d0                  ; set return code
  210.      rts                          ; return
  211.      cnop      0,4 ; align
  212.      ;
  213.      ;      RamLib looks for this romtag
  214.      ;
  215. ROMTag     DC.W      RTC_MATCHWORD               ; RT_MATCHWORD
  216.      DC.L      ROMTag                  ; RT_MATCHTAG
  217.      DC.L      ENDTag                  ; RT_ENDSKIP
  218.      DC.B      RTF_AUTOINIT                  ; RT_FLAGS
  219.      DC.B      VERSION                  ; RT_VERSION
  220.      DC.B      NT_DEVICE                  ; RT_TYPE
  221.      DC.B      0                      ; RT_PRI
  222.      DC.L      Name                      ; RT_NAME
  223.      DC.L      IdString                  ; RT_IDSTRING
  224.      DC.L      Init                      ; RT_INIT
  225.      ;
  226.      ;      Perform device initialization
  227.      ;
  228. InitRoutine:
  229.      exg      d0,a0                   ; swap seglist and base
  230.      move.l   d0,vb_SegList(a0)              ; store seglist in base
  231.      move.l   a6,SysBase                  ; store in global storage
  232.      exg      a0,d0                   ; swap them back
  233.      rts                          ; return
  234.      ;
  235.      ;
  236.      ;
  237.      cnop      0,4 ; align
  238. dev_Open:
  239.      DEBUG1   "Devstart %lx",#Start
  240.      move.l   a5,-(sp)                  ; save registers
  241.      movea.l  a6,a5                   ; save base
  242.      movea.l  SysBase(pc),a6              ; get ExecBase
  243.      ;
  244.      cmp.w      #IOEXTSER_SIZE,MN_LENGTH(a1)          ; IORequest size >= IOEXTSER_SIZE
  245.      blo.w      50$                      ; nope, finish
  246.      ;
  247.      tst.l      d0                      ; unit 0 specified?
  248.      bne.w      50$                      ; nope, error (who cares?)
  249.      ;
  250.      tst.w      LIB_OPENCNT(a5)              ; currently open?
  251.      bne.w      10$                      ; yep, go process
  252.      ;
  253.      move.b   IO_SERFLAGS(a1),vb_SerFlags(a5)     ; save flags
  254.      ;
  255.      tst.b      vb_Initialized(a5)              ; already initialized?
  256.      bne.w      40$                      ; yep, skip initialization
  257.      ;
  258.      move.l   a1,-(sp)                  ; save register
  259.      ;
  260.      lea.l      miscresource(pc),a1              ; ptr to resource name
  261.      jsr      _LVOOpenResource(a6)              ; go open it
  262.      move.l   d0,vb_MiscBase(a5)              ; save base
  263.      ;
  264.      moveq      #MR_SERIALPORT,d0              ; set unit number
  265.      bsr.w      allocResource               ; go allocate it
  266.      tst.l      d0                      ; did we get it?
  267.      bne.b      20$                      ; nope, error
  268.      ;
  269.      moveq      #MR_SERIALBITS,d0              ; set unit number
  270.      bsr.w      allocResource               ; go allocate it
  271.      tst.l      d0                      ; did we get it?
  272.      bne.b      5$                     ; nope, error
  273.      ;
  274.      ;      Get system preferences
  275.      ;
  276.      move.l   a1,-(sp)                  ; save registers
  277.      ;
  278.      lea.l      intuitlib(pc),a1              ; ptr to library name
  279.      moveq      #0,d0                   ; can't use OldOpenLibrary as this will not be supported.
  280.      jsr      _LVOOpenLibrary(a6)              ; go open it (any version)
  281.      movea.l  d0,a6                   ; get intuition base
  282.      ;
  283.      move.l   #(pf_SerParShk+3)&$fffffffc,d0      ; size we need (aligned)
  284.      suba.l   d0,sp                   ; reserve space
  285.      ;
  286.      movea.l  sp,a0                   ; set data area ptr
  287.      jsr      _LVOGetPrefs(a6)              ; get preferences
  288.      ;
  289.      movea.l  a6,a1                   ; get intuition base
  290.      movea.l  SysBase(pc),a6              ; restore ExecBase
  291.      jsr      _LVOCloseLibrary(a6)              ; close it
  292.      ;
  293.      moveq      #$0f,d1                  ; set mask
  294.      and.b      pf_SerStopBuf(sp),d1              ; get bufsize index
  295.      addq.l   #8,d1                   ; calc shift value
  296.      moveq      #2,d0                   ; get 1<<1
  297.      lsl.l      d1,d0                   ; get default bufsize
  298.      move.l   d0,vb_DefRBufLen(a5)              ; and store
  299.      ;
  300.      moveq      #0,d1                   ; clear upper half
  301.      move.w   pf_BaudRate(sp),d1              ; get baud rate
  302.      add.l      d1,d1                   ; generate offset
  303.      move.w   .baudTable(pc,d1.w),d1          ; get default baud
  304.      move.l   d1,vb_DefBaud(a5)              ; and store
  305.      ;
  306.      bsr      internalReset               ; go init baud and buffer
  307.      ;
  308.      lea.l      (pf_SerParShk+3)&$fffffffc(sp),sp   ; restore stack
  309.      movea.l  (sp)+,a1                  ; restore registers
  310.      tst.l      d0                      ; got 'em?
  311.      beq.b      30$                      ; yep, branch
  312.      ;
  313.      moveq      #MR_SERIALBITS,d0              ; set unit
  314.      movea.l  vb_MiscBase(a5),a6              ; get MiscBase
  315.      jsr      _LVOFreeMiscResource(a6)          ; release the resource
  316.      ;
  317. 5$     moveq      #MR_SERIALPORT,d0              ; set unit
  318.      movea.l  vb_MiscBase(a5),a6              ; get MiscBase
  319.      jsr      _LVOFreeMiscResource(a6)          ; release the resource
  320.      movea.l  SysBase(pc),a6              ; restore ExecBase
  321.      ;
  322. 20$     moveq      #SerErr_DevBusy,d0              ; set error status
  323.      bra      50$                      ; go return
  324.      ;
  325.      ;      Preferences baud lookup table
  326.      ;
  327.      cnop      0,4 ; align
  328. .baudTable:
  329.      dc.w      112,300,1200,2400,4800,9600,19200,31250,38400,57600,62400,64800
  330.      ;
  331.      cnop      0,4 ; align
  332. 30$     moveq      #0,d1                   ; clear flags
  333.      moveq      #UNIT_VBLANK,d0              ; set unit
  334.      lea.l      timerReq(pc),a1              ; ptr to timer request
  335.      lea.l      timerdevice(pc),a0              ; ptr to device name
  336.      jsr      _LVOOpenDevice(a6)              ; go open it
  337.      ;
  338.      DISABLE                      ; disable interrupts
  339.      ;
  340.      lea.l      _ciab,a1                  ; get ptr to ciab
  341.      move.b   ciaddra(a1),d0
  342.      move.b   d0,vb_SaveDDRA(a5)              ; save DDR value
  343.      andi.b   #PRTMASK,d0                  ; make serial bits input
  344.      move.b   (a1),d1                  ; ciapra(a1)
  345.      ori.b      #CIAF_COMDTR|CIAF_COMRTS,d0          ; make DTR/RTS output
  346.      move.b   d1,vb_SavePRA(a5)              ; save PR value
  347.      andi.b   #CIAF_COMDTR|CIAF_COMRTS|PRTMASK,d0 ; turn on DTR/RTS
  348.      move.b   d0,ciaddra(a1)
  349.      andi.b   #CIAF_COMCTS|CIAF_COMDSR|PRTMASK,d1 ; make CTS/DSR input
  350.      move.b   d1,(a1)                  ; ciapra(a1)
  351.      ;
  352.      moveq      #INTB_PORTS,d0              ; get interrupt number
  353.      lea.l      VBInterrupt(pc),a1              ; get interrupt ptr
  354.      jsr      _LVOAddIntServer(a6)              ; add it to the list
  355.      ;
  356.      bsr      getVBR                  ; get vector base (in A0)
  357.      ;
  358.      move.l   LVL1VEC(a0),vb_OldLevel1(a5)          ; save original vector
  359.      lea.l      level1(pc),a1               ; get new vector ptr
  360.      move.l   a1,LVL1VEC(a0)              ; set new vector
  361.      ;
  362.      move.l   LVL5VEC(a0),vb_OldLevel5(a5)          ; save original vector
  363.      lea.l      level5(pc),a1               ; get new vector ptr
  364.      move.l   a1,LVL5VEC(a0)              ; set new vector
  365.      ;
  366.      lea.l      _custom,a1                  ; get ptr to custom chips
  367.      move.w   #INTF_RBF|INTF_TBE,intreq(a1)       ; clear pending interrupts
  368.      move.w   #INTF_SETCLR|INTF_RBF|INTF_TBE,intena(a1) ; enable RBF & TBE
  369.      ;
  370.      addq.b   #1,vb_Initialized(a5)           ; set flag
  371.      ;
  372.      movea.l  (sp)+,a1                  ; restore register
  373.      pea.l      40$(pc)
  374.      jmp      _LVOEnable(a6)              ; enable interrupts
  375.      ; go exit
  376.      ;
  377. 10$     moveq      #SerErr_DevBusy,d0              ; preset error status
  378.      btst      #SERB_SHARED,vb_SerFlags(a5)          ; opened shared?
  379.      beq.b      50$                      ; nope, error
  380.      btst      #SERB_SHARED,IO_SERFLAGS(a1)          ; requesting shared?
  381.      beq.b      50$                      ; nope, error
  382.      ;
  383.      ;      Initialize I/O request
  384.      ;
  385. 40$     moveq      #8,d0                   ; get char size
  386.      move.b   d0,IO_READLEN(a1)              ; set read length
  387.      move.b   d0,IO_WRITELEN(a1)              ; set write length
  388.      moveq      #1,d0                   ; get stop bits
  389.      move.b   d0,IO_STOPBITS(a1)              ; set stop bits
  390.      move.b   IO_SERFLAGS(a1),d0
  391.      ori.b      #SERF_XDISABLED|SERF_RAD_BOOGIE|SERF_QUEUEDBRK|SERF_7WIRE,d0 ;flags
  392.      andi.b   #~(SERF_PARTY_ODD|SERF_PARTY_ON),d0 ; not used
  393.      move.b   d0,IO_SERFLAGS(a1)
  394.      move.l   vb_CurBaud(a5),IO_BAUD(a1)          ; set baud
  395.      move.l   vb_CurRBufLen(a5),IO_RBUFLEN(a1)    ; set read buffer length
  396.      ;
  397.      addq.w   #1,LIB_OPENCNT(a5)              ; incr open count
  398.      andi.b   #~(1<<LIBB_DELEXP),LIB_FLAGS(a5)    ; clear expunge bit
  399.      moveq      #0,d0                   ; no error
  400.      ;
  401. 50$     move.b   d0,IO_ERROR(a1)              ; store error code
  402.      movea.l  a5,a6                   ; restore base
  403.      move.l   (sp)+,a5                  ; restore registers
  404.      rts                          ; return
  405.      ;
  406.      ;      Attempt to allocate one of the serial resources.
  407.      ;
  408.      cnop      0,4 ; align
  409. allocResource:
  410.      move.l   a6,-(sp)                  ; save base pointer
  411.      move.l   d0,-(sp)                  ; save unit
  412.      lea.l      Name(pc),a1                  ; get lock name
  413.      move.l   vb_MiscBase(a5),a6              ; get MiscBase
  414.      jsr      _LVOAllocMiscResource(a6)          ; go allocate it
  415.      tst.l      d0                      ; did we get it?
  416.      beq.b      20$                      ; yep, branch
  417.      ;
  418.      ;      It's in use, so we try to locate the device using the string
  419.      ;      returned and attempt to remove it.
  420.      ;
  421.      movea.l  SysBase(pc),a6              ; get ExecBase
  422.      ;
  423.      movea.l  d0,a1                   ; get ptr to serial name
  424.      lea.l      DeviceList(a6),a0              ; get ptr to device list
  425.      jsr      _LVOFindName(a6)              ; go find it
  426.      tst.l      d0                      ; found?
  427.      beq.b      10$                      ; nope, branch
  428.      ;
  429.      movea.l  d0,a1                   ; xfer device ptr
  430.      jsr      _LVORemDevice(a6)              ; remove it
  431.      ;
  432.      ;      We then retry the allocate.
  433.      ;
  434. 10$     move.l   (sp),d0                  ; get unit
  435.      lea.l      Name(pc),a1                  ; get lock name
  436.      movea.l  vb_MiscBase(a5),a6              ; get MiscBase
  437.      jsr      _LVOAllocMiscResource(a6)          ; go allocate it
  438.      ;
  439. 20$     addq.l   #4,sp                   ; restore stack ptr
  440.      movea.l  (sp)+,a6                  ; restore base ptr
  441.      rts                          ; return
  442.      ;
  443.      ;      Set exception vectors
  444.      ;
  445.      cnop      0,4 ; align
  446. getVBR:
  447.      move.l   a5,-(sp)                  ; save registers
  448.      suba.l   a0,a0                   ; ptr to vector base (68000)
  449.      btst      #AFB_68010,AttnFlags+1(a6)          ; 68010 or higher?
  450.      beq.b      10$                      ; nope, go set vector
  451.      lea.l      20$(pc),a5                  ; ptr to routine
  452.      jsr      _LVOSupervisor(a6)              ; get into supervisor state
  453. 10$     movea.l  (sp)+,a5                  ; restore register
  454.      rts                          ; return
  455.      cnop      0,4 ; align
  456. 20$     movec.l  vbr,a0                  ; get vector base
  457.      rte                          ; return
  458.      ;
  459.      ;      Device Close routine
  460.      ;
  461.      cnop      0,4 ; align
  462. dev_Close:
  463.      ;
  464.      moveq      #-1,d0                  ; invalidate
  465.      move.l   d0,IO_DEVICE(a1)              ;   device
  466.      ;
  467.      tst.w      LIB_OPENCNT(a6)
  468.      beq      5$
  469.      subq.w   #1,LIB_OPENCNT(a6)              ; decr open count
  470.      bne.w      dev_Null                  ; still open? yep, branch
  471. 5$
  472.      ;
  473.      btst      #LIBB_DELEXP,LIB_FLAGS(a6)          ; delayed expunge set?
  474.      beq.b      dev_Null                  ; nope, go exit
  475.      ;
  476.      ;      Device Expunge routine (also fall through from dev_Close)
  477.      ;
  478. dev_Expunge:
  479.      ori.b      #1<<LIBB_DELEXP,LIB_FLAGS(a6)       ; Set expunge flag
  480.      tst.w      LIB_OPENCNT(a6)              ; currently open?
  481.      bne.b      dev_Null                  ; yep, so just exit
  482.      ;
  483.      move.l   a5,-(sp)                  ; save registers
  484.      movea.l  a6,a5                   ; save base
  485.      movea.l  SysBase(pc),a6              ; get ExecBase
  486.      ;
  487.      move.l   a1,-(sp)                  ; save registers
  488.      ;
  489.      bsr.b      getVBR                  ; get vector base (in A0)
  490.      ;
  491.      moveq      #1,d0                   ; set not restored code
  492.      ;
  493.      lea.l      level1(pc),a1               ; get our vector ptr
  494.      cmpa.l   LVL1VEC(a0),a1              ; do they match?
  495.      bne      10$                      ; nope, can't restore
  496.      ;
  497.      lea.l      level5(pc),a1               ; get our vector ptr
  498.      cmpa.l   LVL5VEC(a0),a1              ; do they match?
  499.      bne      10$                      ; nope, can't restore
  500.      ;
  501.      DISABLE                      ; disable interrupts
  502.      ;
  503.      move.l   vb_OldLevel1(a5),LVL1VEC(a0)          ; restore original vector
  504.      move.l   vb_OldLevel5(a5),LVL5VEC(a0)          ; restore original vector
  505.      ;
  506.      moveq      #INTB_PORTS,d0              ; get interrupt number
  507.      lea.l      VBInterrupt(pc),a1              ; get interrupt ptr
  508.      jsr      _LVORemIntServer(a6)              ; remove it from the list
  509.      ;
  510.      lea.l      _custom,a0
  511.      move.w   #INTF_RBF|INTF_TBE,d0           ; indicate serial interrupts
  512.      move.w   d0,intena(a0)               ; disable interrupts
  513.      move.w   d0,intreq(a0)               ; clear pending interrupts
  514.      ;
  515.      bsr      freeBuf                  ; free allocated buffers
  516.      ;
  517.      lea.l      _ciab,a0                  ; get pointer to ciab
  518.      move.b   ciaddra(a0),d0              ; get DDR value
  519.      andi.b   #PRTMASK,d0                  ; save printer bits
  520.      ori.b      #~PRTMASK,d0                  ; set serial bits to output
  521.      move.b   d0,ciaddra(a0)              ; store value
  522.      ;
  523.      move.b   (a0),d0                  ; get PR value ( ciapra(a0) )
  524.      andi.b   #PRTMASK,d0                  ; mask out serial bits
  525.      move.b   vb_SavePRA(a5),d1              ; get saved value
  526.      andi.b   #~PRTMASK,d1                  ; mask out printer bits
  527.      or.b      d1,d0                   ; combine the two
  528.      move.b   d0,(a0)                  ; and store ( ciapra(a0) )
  529.      ;
  530.      move.b   ciaddra(a0),d0              ; get DDR value
  531.      andi.b   #PRTMASK,d0                  ; mask out serial bits
  532.      move.b   vb_SaveDDRA(a5),d1              ; get saved value
  533.      andi.b   #~PRTMASK,d1                  ; mask out printer bits
  534.      or.b      d1,d0                   ; combine the two
  535.      move.b   d0,ciaddra(a0)              ; and store
  536.      ;
  537.      lea.l      timerReq(pc),a1              ; get ptr to timer request
  538.      jsr      _LVOCloseDevice(a6)              ; go close it
  539.      ;
  540.      movea.l  vb_MiscBase(a5),a6              ; get MiscBase
  541.      moveq      #MR_SERIALBITS,d0              ; set unit
  542.      jsr      _LVOFreeMiscResource(a6)          ; release the resource
  543.      ;
  544.      moveq      #MR_SERIALPORT,d0              ; set unit
  545.      jsr      _LVOFreeMiscResource(a6)          ; release the resource
  546.      movea.l  SysBase(pc),a6              ; restore ExecBase
  547.      ;
  548.      ENABLE                       ; enable interrupts
  549.      ;
  550.      subq.b   #1,vb_Initialized(a5)           ; clear flag
  551.      moveq      #0,d0                   ; free up everything
  552.      ;
  553. 10$     movea.l  (sp)+,a1                  ; restore registers
  554.      ;
  555.      movea.l  a5,a6                   ; restore base
  556.      movea.l  (sp)+,a5                  ; restore registers
  557.      ;
  558.      tst.l      d0                      ; freed?
  559.      bne.b      dev_Null                  ; nope, can't expunge, exit
  560.      ;
  561.      clr.b      vb_SerFlags(a6)              ; clear flags
  562.      move.l   vb_SegList(a6),d0              ; get seglist ptr
  563.      move.l   d0,-(sp)                  ; save registers (save D0!)
  564.      ;
  565.      movea.l  a6,a1                   ; get base
  566.      ; This is the REMOVE macro
  567.      move.l   (a1)+,a0
  568.      move.l   (a1),a1                  ; LN+PRED
  569.      move.l   a0,(a1)
  570.      move.l   a1,LN_PRED(a0)
  571.      ;
  572.      movea.l  a6,a1                   ; get base
  573.      moveq      #0,d0                   ; clear work
  574.      move.w   LIB_NEGSIZE(a6),d0              ; calculate
  575.      suba.w   d0,a1                   ;   memory address
  576.      add.w      LIB_POSSIZE(a6),d0              ;     and size
  577.      move.l   a6,-(sp)                  ; save registers
  578.      movea.l  SysBase(pc),a6              ; get ExecBase
  579.      jsr      _LVOFreeMem(a6)              ; free it
  580.      ;
  581.      move.l   (sp)+,a6                  ; restore registers
  582.      move.l   (sp)+,d0                  ; restore registers
  583. exp_end  rts                          ; return (seglist in D0!)
  584.      ;
  585.      ;      Device "ExtFunc" routine
  586.      ;
  587.      cnop      0,4 ; align
  588. dev_Null:
  589.      moveq      #0,d0                   ; set return code
  590.      bra.b      exp_end                  ; return
  591.      ;
  592.      ;
  593.      ;
  594.      cnop      0,4 ; align
  595.      IFNE      DEBUG
  596. printIO:
  597.      movem.l  d0-d7/a0-a6,-(sp)
  598.      addq.l   #1,ioctr
  599.      move.l   ioctr,-(sp)
  600.      move.l   a1,-(sp)
  601.      move.l   a0,-(sp)
  602.      pea.l      0$
  603.      pea.l      Name
  604.      DISABLE  TBE|INTF_PORTS
  605.      jsr      _SendText(pc)
  606.      ENABLE   TBE|INTF_PORTS
  607.      lea.l      20(sp),sp
  608.  
  609.      moveq      #0,d0
  610.      move.w   IO_COMMAND(a1),d0
  611.      move.l   d0,-(sp)
  612.      move.l   MN_REPLYPORT(a1),-(sp)
  613.      moveq      #0,d0
  614.      move.b   LN_TYPE(a1),d0
  615.      move.l   d0,-(sp)
  616.      pea.l      1$
  617.      pea.l      Name
  618.      DISABLE  TBE|INTF_PORTS
  619.      jsr      _SendText(pc)
  620.      ENABLE   TBE|INTF_PORTS
  621.      lea.l      20(sp),sp
  622.  
  623.      move.l   IO_LENGTH(a1),-(sp)
  624.      moveq      #0,d0
  625.      move.b   IO_ERROR(a1),d0
  626.      move.l   d0,-(sp)
  627.      move.b   IO_FLAGS(a1),d0
  628.      move.l   d0,-(sp)
  629.      pea.l      2$
  630.      pea.l      Name
  631.      DISABLE  TBE|INTF_PORTS
  632.      jsr      _SendText(pc)
  633.      ENABLE   TBE|INTF_PORTS
  634.      lea.l      20(sp),sp
  635.  
  636.      move.l   IO_EXTFLAGS(a1),-(sp)
  637.      move.l   IO_RBUFLEN(a1),-(sp)
  638.      move.l   IO_ACTUAL(a1),-(sp)
  639.      pea.l      3$
  640.      pea.l      Name
  641.      DISABLE  TBE|INTF_PORTS
  642.      jsr      _SendText(pc)
  643.      ENABLE   TBE|INTF_PORTS
  644.      lea.l      20(sp),sp
  645.  
  646.      moveq      #0,d0
  647.      move.b   IO_WRITELEN(a1),d0
  648.      move.l   d0,-(sp)
  649.      move.b   IO_READLEN(a1),d0
  650.      move.l   d0,-(sp)
  651.      move.l   IO_BAUD(a1),-(sp)
  652.      pea.l      4$
  653.      pea.l      Name
  654.      DISABLE  TBE|INTF_PORTS
  655.      jsr      _SendText(pc)
  656.      ENABLE   TBE|INTF_PORTS
  657.      lea.l      20(sp),sp
  658.  
  659.      moveq      #0,d0
  660.      move.w   IO_STATUS(a1),d0
  661.      move.l   d0,-(sp)
  662.      moveq      #0,d0
  663.      move.b   IO_SERFLAGS(a1),d0
  664.      move.l   d0,-(sp)
  665.      move.b   IO_STOPBITS(a1),d0
  666.      move.l   d0,-(sp)
  667.      pea.l      5$
  668.      pea.l      Name
  669.      DISABLE  TBE|INTF_PORTS
  670.      jsr      _SendText(pc)
  671.      ENABLE   TBE|INTF_PORTS
  672.      lea.l      20(sp),sp
  673.      movem.l  (sp)+,d0-d7/a0-a6
  674.      rts
  675.      cnop      0,4 ; align
  676. 0$     dc.b      '%ls - I/O     %8lx, Cnt = %ld',0
  677. 1$     DC.B      'Type    %8ld     ReplyPort %8lx    Command  %8ld',0
  678. 2$     DC.B      'Flags   %8lx     Error     %8ld    Length   %8ld',0
  679. 3$     DC.B      'Actual  %8ld     RBufLen   %8ld    ExtFlags %8lx',0
  680. 4$     DC.B      'Baud    %8ld     ReadLen   %8ld    WriteLen %8ld',0
  681. 5$     DC.B      'StopBit %8ld     SerFlags  %8lx    Status   %8lx',0
  682.      ;
  683.      ;
  684.      ;
  685. abortIOs dc.b      'Abort Start',0
  686. abortIOe dc.b      'Abort End',0
  687. abortIOa dc.b      'Aborting',0
  688. beginIOs dc.b      'Begin Start',0
  689. beginIOe dc.b      'Begin End',0
  690. openIO     dc.b      'Open IO',0
  691. replyIO  dc.b      'replyIO',0
  692.      ds.l      0
  693. ioctr     dc.l      0
  694.      ENDC
  695.      ;
  696. cmdTable dc.w      cmd_Invalid-cmdTable              ; CMD_INVALID
  697.      dc.w      cmd_Reset-cmdTable              ; CMD_RESET
  698.      dc.w      cmd_Read-cmdTable              ; CMD_READ
  699.      dc.w      cmd_Write-cmdTable              ; CMD_WRITE
  700.      dc.w      cmd_Invalid-cmdTable              ; CMD_UPDATE
  701.      dc.w      cmd_Clear-cmdTable              ; CMD_CLEAR
  702.      dc.w      cmd_Invalid-cmdTable              ; CMD_STOP
  703.      dc.w      cmd_Invalid-cmdTable              ; CMD_START
  704.      dc.w      cmd_Flush-cmdTable              ; CMD_FLUSH
  705.      dc.w      sdcmd_Query-cmdTable              ; SDCMD_QUERY
  706.      dc.w      sdcmd_Break-cmdTable              ; SDCMD_BREAK
  707.      dc.w      sdcmd_SetParams-cmdTable          ; SDCMD_SETPARAMS
  708. endTable dc.w      nscmd_DeviceQuery-cmdTable          ; NSCMD_DEVICEQUERY
  709.      ;
  710.      ;      Device BeginIO routine
  711.      ;
  712. dev_BeginIO:
  713.      move.l   a5,-(sp)                  ; save register
  714.      movea.l  a6,a5                   ; save base
  715.      movea.l  SysBase(pc),a6              ; get ExecBase
  716.      DEBUGIO  beginIOs
  717.      ;
  718.      move.b   #NT_MESSAGE,LN_TYPE(a1)          ; set type
  719.      clr.b      IO_ERROR(a1)                  ; clear error
  720.      ;
  721.      andi.b   #~(IOSERF_QUEUED|IOSERF_ACTIVE),IO_FLAGS(a1) ; clear flags
  722.      ;
  723.      move.w   IO_COMMAND(a1),d0              ; get command
  724.      add.w      d0,d0                   ; multiply by 2
  725.      cmpi.w   #endTable-cmdTable,d0           ; in range?
  726.      bhi.b      25$                      ; nope, error
  727.      ;
  728. 5$     move.w   cmdTable(pc,d0.w),d0              ; get routine offset
  729.      jsr      cmdTable(pc,d0.w)              ; go do it
  730.      tst.l      d0                      ; I/O completed?
  731.      bne.b      19$                      ; nope, go return
  732.      ;
  733. 10$     DEBUGIO  beginIOe
  734.      btst      #IOB_QUICK,IO_FLAGS(a1)          ; need to reply?
  735.      bne.b      20$                      ; nope, branch
  736. 15$     jsr      _LVOReplyMsg(a6)              ; send it back
  737.      ;
  738. 19$     andi.b   #~(1<<IOB_QUICK),IO_FLAGS(a1)         ; clear quick bit
  739. 20$     movea.l  a5,a6                   ; restore base
  740.      movea.l  (sp)+,a5                  ; restore register
  741.      rts                          ; return
  742.      ;
  743.      cnop      0,4 ; align
  744. 25$     move.w   IO_COMMAND(a1),d0              ; get command
  745.      cmpi.w   #NSCMD_DEVICEQUERY,d0
  746.      bne.b      30$
  747.      moveq      #24,d0
  748.      bra.b      5$
  749.      ;
  750.      cnop      0,4 ; align
  751. 30$     move.b   #IOERR_NOCMD,IO_ERROR(a1)          ; invalid command
  752.      bra.b      10$                      ; branch
  753.      ;
  754.      ;      Device AbortIO routine
  755.      ;
  756.      cnop      0,4 ; align
  757. dev_AbortIO:
  758.      move.l   a5,-(sp)                  ; save registers
  759.      movea.l  a6,a5                   ; save base
  760.      movea.l  SysBase(pc),a6              ; get ExecBase
  761.      DEBUGIO  abortIOs
  762.      ;
  763.      DISABLE                      ; disable interrupts
  764.      ;
  765.      move.b   IO_FLAGS(a1),d1
  766.      btst      #IOSERB_QUEUED,d1              ; queued request?
  767.      bne.b      40$                      ; yep, branch
  768.      ;
  769.      btst      #1<<IOSERB_ACTIVE,d1              ; active request?
  770.      beq.b      10$                      ; nope, just exit
  771.      ;
  772.      move.w   IO_COMMAND(a1),d0              ; get command
  773.      subq.w   #CMD_READ,d0                  ; was it a read?
  774.      beq.b      20$                      ; yep, go process
  775.      ;
  776.      subq.w   #CMD_WRITE-CMD_READ,d0          ; was it a write?
  777.      beq.b      30$                      ; yep, go process
  778.      ;
  779.      subq.w   #SDCMD_BREAK-CMD_WRITE,d0          ; was it a break?
  780.      beq.b      30$                      ; yep, go process
  781.      ;
  782.      ;      Fall through or enter from below
  783.      ;
  784. 10$     ENABLE                       ; enable ints and return
  785. 15$     movea.l  a5,a6                   ; restore base
  786.      movea.l  (sp)+,a5                  ; restore registers
  787.      rts                          ; return
  788.      ;
  789.      ;      Abort an active read request
  790.      ;
  791.      cnop      0,4 ; align
  792. 20$     clr.l      cr_IOReq                  ; no longer active
  793.      bra.b      50$                      ; go set flags
  794.      ;
  795.      ;      Abort an active write request
  796.      ;
  797.      cnop      0,4 ; align
  798. 30$     clr.l      cw_Length                  ; no longer active
  799.      clr.l      cw_IOReq                  ; no longer active
  800.      move.l   cw_Buffer(pc),d0              ; get buffer ptr
  801.      sub.l      IO_DATA(a1),d0              ; calc number of bytes xfer'd
  802.      move.l   d0,IO_ACTUAL(a1)              ; store
  803.      ;
  804.      ;      Force a TBE interrupt to get the next write going.
  805.      ;
  806.      move.w   #INTF_SETCLR|INTF_TBE,_intreq       ; make TBE pending
  807.      bra.b      50$                      ; go set flags
  808.      ;
  809.      ;      Remove I/O from queue.
  810.      ;
  811.      cnop      0,4 ; align
  812. 40$     move.l   a1,-(sp)                  ; save ptr
  813.      ; This is the REMOVE macro
  814.      move.l   (a1)+,a0
  815.      move.l   (a1),a1                  ; LN+PRED
  816.      move.l   a0,(a1)
  817.      move.l   a1,LN_PRED(a0)
  818.      ;
  819.      movea.l  (sp)+,a1                  ; restore ptr
  820.      ;
  821.      ;      Set error and return I/O
  822.      ;
  823. 50$     move.b   #IOERR_ABORTED,IO_ERROR(a1)          ; set error code
  824.      move.b   IO_FLAGS(a1),d1              ; get flags
  825.      ori.b      #1<<IOSERB_ABORT,d1              ; set abort flag
  826.      andi.b   #~(IOSERF_QUEUED|IOSERF_ACTIVE),d1  ; clear flags
  827.      move.b   d1,IO_FLAGS(a1)              ; store flags
  828.      DEBUGIO  abortIOe
  829.      btst      #1<<IOB_QUICK,d1              ; need to reply?
  830.      bne.b      10$                      ; nope, branch
  831.      pea      10$(pc)                  ; branch to return
  832.      jmp      _LVOReplyMsg(a6)              ; send it back
  833.      ;
  834.      ;      Abort all active/queued commands and reset internal state
  835.      ;
  836. cmd_Reset:
  837.      move.l   a1,-(sp)                  ; save I/O request
  838.      bsr.b      cmd_Flush                  ; go abort queued requests
  839.      ;
  840.      DISABLE                      ; disable interrupts
  841.      ;
  842.      ;      This must follow the DISABLE
  843.      ;
  844.      exg      a5,a6                   ; exchange base and ExecBase
  845.      ;
  846.      move.l   cr_IOReq(pc),d0              ; active read?
  847.      beq.b      10$                      ; nope, branch
  848.      movea.l  d0,a1                   ; get I/O request
  849.      bsr      dev_AbortIO                  ; go abort it
  850.      ;
  851.      ;
  852.      ;
  853. 10$     move.l   cw_IOReq(pc),d0              ; active write?
  854.      beq.b      20$                      ; nope, branch
  855.      movea.l  d0,a1                   ; get I/O request
  856.      bsr      dev_AbortIO                  ; go abort it
  857.      ;
  858. 20$     exg      a5,a6                   ; restore base and ExecBase
  859.      movea.l  (sp)+,a1                  ; restore I/O request
  860.      moveq      #8,d0                   ; get char size
  861.      move.b   d0,IO_READLEN(a1)              ; set read length
  862.      move.b   d0,IO_WRITELEN(a1)              ; set write length
  863.      moveq      #1,d0                   ; get stop bits
  864.      move.b   d0,IO_STOPBITS(a1)              ; set stop bits
  865.      move.l   vb_DefBaud(a5),IO_BAUD(a1)          ; set to default baud
  866.      move.l   vb_DefRBufLen(a5),IO_RBUFLEN(a1)    ; set to default buflen
  867.      bsr      internalReset               ; go set/verify parameters
  868.      move.b   d0,IO_ERROR(a1)              ; set error code
  869.      ;
  870.      ;      Set RC
  871.      ;
  872.      moveq      #0,d0                   ; I/O complete
  873.      jmp      _LVOEnable(a6)              ; enable interrupts
  874.                               ; return
  875.      ;
  876.      ;      Abort all "queued" requests, leaving all active alone.
  877.      ;
  878.      cnop      0,4 ; align
  879. cmd_Flush:
  880.      move.l   a2,-(sp)                  ; save registers
  881.      move.l   a1,-(sp)                  ; save registers
  882.      DISABLE                      ; disable interrupts
  883.      ;
  884.      ;      Abort all queued read requests.
  885.      ;
  886.      lea.l      readQ(pc),a2                  ; get ptr to read queue
  887.      bsr.b      20$                      ; branch to abort
  888.      ;
  889.      ;      Abort all queued write requests.
  890.      ;
  891.      lea.l      writeQ(pc),a2               ; get ptr to write queue
  892.      bsr.b      20$                      ; branch to abort
  893.      ;
  894.      ;      Enable, restore, and return to caller
  895.      ;
  896.      ENABLE                       ; enable interrupts
  897.      move.l   (sp)+,a1                  ; restore registers
  898.      move.l   (sp)+,a2                  ; restore registers
  899.      ;
  900.      ;      Set RC and return
  901.      ;
  902.      moveq      #0,d0                   ; I/O complete
  903.      ;
  904.      ;      !!!NOTE!!!  In a mad attempt to save 2 bytes, this RTS is used
  905.      ;      by the subroutine below.  Why waste 'em?  B-)
  906.      ;
  907. 10$     rts                          ; return ( used below too!! )
  908.      cnop      0,4 ; align
  909.      ;
  910.      ;      Subroutine to remove and reply each I/O request.
  911.      ;
  912. 20$     movea.l  a2,a0                   ; get list ptr
  913.      ; This is the REMHEAD macro
  914. 25$     move.l    (a0),a1
  915.      move.l    (a1),d0
  916.      beq.b       25$
  917.      move.l    d0,(a0)
  918.      exg.l       d0,a1
  919.      move.l    a0,LN_PRED(a1)
  920.      ;
  921.      tst.l      d0                      ; end of list?
  922.      beq.b      10$                      ; yep, branch to return
  923.      ;
  924.      movea.l  d0,a1                   ; get I/O request
  925.      andi.b   #~(1<<IOSERB_QUEUED),IO_FLAGS(a1)   ; no longer queued
  926.      moveq      #IOERR_ABORTED,d0              ; indicate aborted
  927.      move.b   d0,IO_ERROR(a1)              ; store status
  928.      ;
  929.      pea.l      20$(pc)                  ; continue with next
  930.      jmp      _LVOReplyMsg(a6)              ; send it back
  931.      ;
  932.      ;      Process a CMD_READ request.
  933.      ;
  934. cmd_Read:
  935.      ;
  936.      ;      Zero length requests just get returned.
  937.      ;
  938.      clr.l      IO_ACTUAL(a1)               ; clear bytes read
  939.      move.l   IO_LENGTH(a1),d0              ; get length and test
  940.      beq.b      20$                      ; yep, leave
  941.      ;
  942.      ;      This can be used to circumvent a bug in NComm 3.0 which
  943.      ;      references the buffer even when there was nothing read.
  944.      ;
  945.     IFNE     NCOMM
  946.      move.l   IO_DATA(A1),a0              ; get data pointer
  947.      clr.b      (a0)                      ; clear first byte in buffer
  948.     ENDC
  949.      ;
  950.      ;      The disable counter works just like exec's TDNestCnt field.  It's
  951.      ;      initialized to -1.  After incrementing, if it is 0, then we
  952.      ;      can attempt to process this request immediately.  If it's > 0,
  953.      ;      then we're already disabled and we must queue this request.
  954.      ;
  955.      addq.b   #1,disableRead              ; incr disable count
  956.      bgt.b      50$                      ; >0, already disabled
  957.      ;
  958.      ;      If we're already processing an request, this one has to wait
  959.      ;      until that one is done, so go queue it.
  960.      ;
  961.      move.l   cr_IOReq(pc),d1              ; have an active request?
  962.      bne.b      50$                      ; yep, go queue this one
  963.      ;
  964.      ;      If we don't have enough bytes to satisfy this request then go
  965.      ;      queue it.
  966.      ;
  967.      cmp.l      i_InCnt(pc),d0              ; length > current bytes?
  968.      bgt.b      50$                      ; yep, go queue it
  969.      ;
  970.      ;      Setup fields and go copy the data
  971.      ;
  972.      move.l   IO_DATA(a1),cr_OutPtr           ; get/set output ptr
  973.      move.l   IO_LENGTH(a1),cr_Length          ; get/set output count
  974.      bsr      copyData                  ; go copy 'em
  975.      moveq      #0,d0                   ; I/O complete
  976.      ;
  977.      ;      We're done, so back off the disable counter.
  978.      ;
  979. 10$     subq.b   #1,disableRead              ; decr disable count
  980.      ;
  981.      ;      Return to caller
  982.      ;
  983. 20$     rts                          ; return
  984.      ;
  985.      ;      Just set flags and queue.  The read interrupt will handle it.
  986.      ;
  987.      cnop      0,4 ; align
  988. 50$     ori.b      #1<<IOSERB_QUEUED,IO_FLAGS(a1)      ; indicate queued
  989.      ;
  990.      ;      Add this request to the end.
  991.      ;
  992.      DISABLE                      ; disable interrupts
  993.      lea.l      readQ(pc),a0                  ; get pointer to read queue
  994.      ; This is the ADDTAIL macro
  995.      addq.l   #LH_TAIL,a0
  996.      move.l   LN_PRED(a0),d0
  997.      move.l   a1,LN_PRED(a0)
  998.      exg      d0,a0
  999.      movem.l  d0/a0,(a1)
  1000.      move.l   a1,(a0)
  1001.      ;
  1002.      ;      Indicate that this request was not handled immediatly.
  1003.      ;
  1004.      moveq      #1,d0                   ; I/O not complete
  1005.      ;
  1006.      pea.l      10$(pc)                  ; branch to return
  1007.      jmp      _LVOEnable(a6)              ; enable interrupts
  1008.      ;
  1009.      ;      Process a CMD_WRITE request.
  1010.      ;
  1011.      cnop      0,4 ; align
  1012. cmd_Write:
  1013.      clr.l      IO_ACTUAL(a1)               ; clear bytes written
  1014.      tst.l      IO_LENGTH(a1)               ; get length and test
  1015.      bne.b      sdcmd_Break                  ; nope, proccess
  1016.      rts
  1017.      ;
  1018.      ;      Entry point for Break command and fall through from cmd_Write.
  1019.      ;
  1020.      cnop      0,4 ; align
  1021. sdcmd_Break:
  1022.      ;
  1023.      ;      Just set flags and queue. The TBE interrupt will handle it.
  1024.      ;
  1025.      ori.b      #1<<IOSERB_QUEUED,IO_FLAGS(a1)      ; indicate queued
  1026.      ;
  1027.      ;      Protect.
  1028.      ;
  1029.      DISABLE                      ; disable interrupts
  1030.      ;
  1031.      ;      Add request to end of queue.
  1032.      ;
  1033.      lea.l      writeQ(pc),a0               ; get queue list ptr
  1034.      ; This is the ADDTAIL macro
  1035.      addq.l   #LH_TAIL,a0
  1036.      move.l   LN_PRED(a0),d0
  1037.      move.l   a1,LN_PRED(a0)
  1038.      exg      d0,a0
  1039.      movem.l  d0/a0,(a1)
  1040.      move.l   a1,(a0)
  1041.      ;
  1042.      ;      If we have an active request, don't force interrupt.
  1043.      ;
  1044.      move.l   cw_IOReq(pc),d0              ; have an active request?
  1045.      bne.b      10$                      ; yep, branch
  1046.      ;
  1047.      ;      Force a TBE interrupt to get the writes going.
  1048.      ;
  1049.      move.w   #INTF_SETCLR|INTF_TBE,_intreq       ; make TBE pending
  1050.      ;
  1051.      ;      Enable, set RC and return to caller.
  1052.      ;
  1053. 10$     moveq      #1,d0                   ; I/O not complete
  1054.      jmp      _LVOEnable(a6)              ; enable interrupts
  1055.                               ; return
  1056.      ;
  1057.      ;      Resets serial read buffer
  1058.      ;
  1059.      ;      Since this routine is called internally, it must NOT reference
  1060.      ;      the I/O request.
  1061.      ;
  1062.      cnop      0,4 ; align
  1063. cmd_Clear:
  1064.      DISABLE                      ; disable interrupts
  1065.      ;
  1066.      ;      Load registers
  1067.      ;
  1068.      move.l   vb_CurRBuf(a5),d0              ; get internal buffer ptr
  1069.      move.l   vb_CurRBufLen(a5),d1              ; and internal buffer len
  1070.      lea.l      i_BufPtr(pc),a0              ; get ptr internal control
  1071.      ;
  1072.      ;      Initialize global buffer variables
  1073.      ;
  1074.      move.l   d0,(a0)+                  ; store buffer ptr
  1075.      move.l   d0,(a0)+                  ; set current input ptr
  1076.      move.l   d0,(a0)+                  ; set current output ptr
  1077.      add.l      d1,d0                   ; add buffer length
  1078.      move.l   d0,(a0)+                  ; store ptr to end of buffer
  1079.      clr.l      (a0)+                   ; clear byte cnt
  1080.      move.l   vb_CurBaud(a5),d0              ; get internal baud
  1081.      lsr.l      #4,d0                   ; divide by 16
  1082.      sub.l      d0,d1                   ; subtract from length
  1083.      move.l   d1,(a0)                  ; set threshold
  1084.      ;
  1085.      ;      Enable, set RC and return.
  1086.      ;
  1087.      moveq      #0,d0                   ; I/O complete
  1088.      jmp      _LVOEnable(a6)              ; enable interrupts
  1089.                               ; return
  1090.      ;
  1091.      ;
  1092.      ;
  1093.      cnop      0,4 ; align
  1094. cmd_Invalid
  1095.      move.b   #IOERR_NOCMD,IO_ERROR(a1)          ; set bad status
  1096.      moveq      #0,d0                   ; I/O complete
  1097.      rts                          ; return
  1098.      ;
  1099.      ;      Returns number of bytes currently in internal buffer and
  1100.      ;      current serial port status.
  1101.      ;
  1102.      ;      NOTE:  Not completely compatible with standard serial.device
  1103.      ;      since it doesn't return the upper byte of IO_STATUS.
  1104.      ;
  1105.      cnop      0,4 ; align
  1106. sdcmd_Query:
  1107.      DISABLE                      ; disable interrupts
  1108.      moveq      #0,d0                   ; clear d0
  1109.      move.b   _ciabpra,d0                  ; get PR register
  1110.      andi.b   #~PRTMASK,d0                  ; zap printer bits
  1111.      ;
  1112.      ;      Uncomment the following to turn on the DSR bit.  This was done
  1113.      ;      for a user whose DSR pin did not function.
  1114.      ;
  1115.     IFNE SETDSR
  1116.      andi.b   #~(1<<CIAB_COMDSR),d0             ; set DSR
  1117.     ENDC
  1118.      ;
  1119.      ;
  1120.      ;
  1121.      move.w   d0,IO_STATUS(a1)              ; store status
  1122.      move.l   i_InCnt(pc),IO_ACTUAL(a1)          ; byte left in buffer
  1123.      ;
  1124.      ;      Enable, set RC and return.
  1125.      ;
  1126.      moveq      #0,d0                   ; I/O complete
  1127.      jmp      _LVOEnable(a6)              ; enable interrupts
  1128.                               ; return
  1129.      ;
  1130.      ;
  1131.      ;
  1132.      cnop      0,4 ; align
  1133. sdcmd_SetParams:
  1134.      ;
  1135.      ;      Validate the read, write, and stop bit lengths.
  1136.      ;
  1137.      moveq      #8,d0                   ; get char length
  1138.      cmp.b      IO_READLEN(a1),d0              ; 8 bit chars for read?
  1139.      bne.b      40$                      ; nope, branch
  1140.      cmp.b      IO_WRITELEN(a1),d0              ; 8 bit chars for write?
  1141.      bne.b      40$                      ; nope, branch
  1142.      moveq      #1,d0                   ; get stop bits
  1143.      cmp.b      IO_STOPBITS(a1),d0              ; 1 stop bit?
  1144.      bne.b      40$                      ; nope, branch
  1145.      ;
  1146.      ;      Get and validate the baud rate.
  1147.      ;
  1148.      move.l   IO_BAUD(a1),d1              ; get baud from I/O req
  1149.      bne.b      20$                      ; specified?
  1150.      move.l   vb_CurBaud(a5),d1              ; get current baud from base
  1151.      bne.b      20$                      ; specified?
  1152.      move.l   vb_DefBaud(a5),d1              ; get default baud from base
  1153. 20$     cmpi.l   #110,d1                  ; too low?
  1154.      blt.b      40$                      ; error
  1155.      cmpi.l   #292000,d1                  ; too high?
  1156.      bgt.b      40$                      ; error
  1157.      ;
  1158.      ;      Get and validate the buffer length.
  1159.      ;
  1160.      move.l   IO_RBUFLEN(a1),d0              ; get buffer length
  1161.      bne.b      30$                      ; specified?
  1162.      move.l   vb_CurRBufLen(a5),d0              ; get current from base
  1163.      bne.b      30$                      ; specified?
  1164.      move.l   vb_DefRBufLen(a5),d0              ; get default from base
  1165.      ;
  1166. 30$     bsr.b      internalReset               ; go init baud and buffer
  1167. 35$     move.b   d0,IO_ERROR(a1)              ; set error code
  1168.      bne.b      39$
  1169.      ;
  1170.      ;      If the 7wire bit is not on, we will only use 3-wire protocol
  1171.      ;
  1172.      moveq      #0,d0                   ; clear flag
  1173.      btst      #SERB_7WIRE,IO_SERFLAGS(a1)          ; use 7wire handshaking?
  1174.      beq.b      36$                      ; nope, branch
  1175.      moveq      #1,d0                   ; set flag
  1176. 36$     move.b   d0,Handshake                  ; store flag
  1177.      ;
  1178.      ;      Set RC and return.
  1179.      ;
  1180. 39$     moveq      #0,d0                   ; I/O complete
  1181.      rts                          ; return
  1182.      ;
  1183.      ;      Invalid parm detected.
  1184.      ;
  1185.      cnop      0,4 ; align
  1186. 40$     moveq      #SerErr_InvParam,d0              ; set error
  1187.      bra.b      35$                      ; go return
  1188.      ;
  1189.      cnop      0,4 ; align
  1190. nscmd_DeviceQuery:
  1191.      move.l   IO_DATA(a1),a0
  1192.      beq.b      10$
  1193.      moveq      #NSDEVICEQUERYRESULT_SIZE,d0
  1194.      move.l   d0,SIZEAVAILABLE(a0)
  1195.      move.l   d0,IO_ACTUAL(a1)
  1196.      move.w   #NSDEVTYPE_SERIAL,DEVICETYPE(a0)
  1197.      move.l   a1,-(sp)
  1198.      lea.l      cmdlist(pc),a1
  1199.      move.l   a1,SUPPORTEDCOMMANDS(a0)
  1200.      move.l   (sp)+,a1
  1201. 10$     moveq      #0,d0
  1202.      rts
  1203.      ;
  1204.      ;      Reset the buffer and baud rate
  1205.      ;
  1206.      ;      Registers:  D0 = Buffer length
  1207.      ;              D1 = Baud rate
  1208.      ;
  1209.      cnop      0,4 ; align
  1210. internalReset:
  1211.      ;
  1212.      ;      Disable interrupts.
  1213.      ;
  1214.      DISABLE                      ; disable interrupts
  1215.      ;
  1216.      ;      Save buffer length and go set serper.
  1217.      ;
  1218.      move.l   d0,-(sp)                  ; save D0
  1219.      move.l   d1,d0                   ; get baud rate
  1220.      ;
  1221.      ;      Set serial period register
  1222.      ;
  1223.      cmp.l      vb_CurBaud(a5),d0              ; current baud = new baud?
  1224.      beq.b      40$                      ; yep, just exit
  1225.      move.l   d0,vb_CurBaud(a5)              ; save new baud
  1226.      move.l   d0,d1                   ; save again
  1227.      lsl.l      #3,d0                   ; baud *= 8
  1228.      sub.l      d1,d0                   ; baud -= saved baud
  1229.      move.l   #25000000,d1                  ; get NTSC base
  1230.      cmpi.b   #50,PowerSupplyFrequency(a6)          ; PAL machine?
  1231.      bne.b      5$                      ; nope, branch
  1232.      move.l   #24772416,d1                  ; get PAL base
  1233. 5$     cmpi.l   #$FFFF,d0                  ; Divide
  1234.      ble.b      20$                      ;
  1235.      lsr.l      #5,d0                   ;
  1236.      divu.w   d0,d1                   ;
  1237.      andi.l   #$FFFF,d1                  ;
  1238.      lsr.l      #5,d1                   ;
  1239.      bra.b      30$                      ;
  1240.      cnop      0,4 ; align
  1241. 20$     divu.w   d0,d1                   ;
  1242. 30$     move.w   d1,_serper                  ; set period value
  1243. 40$
  1244.      move.l   (sp)+,d0                  ; restore D0
  1245.      ;
  1246.      ;      Determine if the buffer length is adequate for the selected CPS.
  1247.      ;      If not, use 64K for the length.
  1248.      ;
  1249.      move.l   vb_CurBaud(a5),d1              ; get current baud
  1250.      lsr.l      #$3,d1                  ; divide by 8
  1251.      cmp.l      d1,d0                   ; buflen > CPS
  1252.      bhi.b      10$                      ; yep, branch
  1253.      move.l   #65536,d0                  ; else use 64K
  1254.      ;
  1255.      ;      Allocate new internal buffer
  1256.      ;
  1257. 10$     cmp.l      vb_CurRBufLen(a5),d0              ; len same as previous?
  1258.      beq.b      6$                      ; yep, so no need to alloc
  1259.      move.l   d0,d1                   ; save length
  1260.      move.l   a1,-(sp)                  ; save registers
  1261.      move.l   d1,-(sp)                  ; save registers
  1262.      moveq      #MEMF_PUBLIC,d1              ; public memory
  1263.      jsr      _LVOAllocMem(a6)              ; go allocate it
  1264.      move.l   (sp)+,d1                  ; restore registers
  1265.      move.l   (sp)+,a1                  ; restore registers
  1266.      tst.l      d0                      ; did we get it?
  1267.      beq.b      21$                      ; if zero, error
  1268.      bsr.b      freeBuf                  ; go free previous buffer
  1269.      move.l   d0,vb_CurRBuf(a5)              ; store new ptr
  1270.      move.l   d1,vb_CurRBufLen(a5)              ; and length
  1271.      bsr      cmd_Clear                  ; go setup buffer
  1272. 6$     moveq      #0,d0                   ; success
  1273.      bra.b      22$                      ; return
  1274.      cnop      0,4 ; align
  1275. 21$     moveq      #SerErr_BufErr,d0              ; set error status
  1276. 22$
  1277.      ;
  1278.      ;      Enable and return to caller.
  1279.      ;
  1280.      jmp      _LVOEnable(a6)              ; enable interrupts
  1281.                               ; return (D0 has status)
  1282.      ;
  1283.      ;      Free internal buffer
  1284.      ;
  1285.      cnop      0,4 ; align
  1286. freeBuf:
  1287.      movem.l  d0-d1/a0-a1,-(sp)              ; save registers
  1288.      move.l   vb_CurRBuf(a5),d0              ; is one there?
  1289.      beq.b      10$                      ; no so branch
  1290.      movea.l  d0,a1                   ; get ptr
  1291.      move.l   vb_CurRBufLen(a5),d0              ; get length
  1292.      clr.l      vb_CurRBuf(a5)              ; clear
  1293.      clr.l      vb_CurRBufLen(a5)              ; clear
  1294.      jsr      _LVOFreeMem(a6)              ; free it
  1295. 10$     movem.l  (sp)+,d0-d1/a0-a1              ; restore registers
  1296.      rts                          ; return
  1297.      ;
  1298.      ;      Checks CTS status and if clear generates a TBE interrupt or
  1299.      ;      requeues the timer request.
  1300.      ;
  1301.      ;      Entered from Exec using the MsgPort callback.
  1302.      ;
  1303.      ;      Input:   a6 = ExecBase
  1304.      ;      Output:  none
  1305.      ;
  1306.      ;      No need to preserve d0/d1/a0/a1
  1307.      ;
  1308.      cnop      0,4 ; align
  1309. timerRtn:
  1310.      lea.l      timerReq(pc),a1              ; get ptr to timer request
  1311.      ; This is the REMOVE macro
  1312.      move.l   (a1)+,a0
  1313.      move.l   (a1),a1                  ; LN+PRED
  1314.      move.l   a0,(a1)
  1315.      move.l   a1,LN_PRED(a0)
  1316.      ;
  1317.      ;      If we were breaking, reset adkcon.
  1318.      ;
  1319.      lea      _custom,a0                  ; get ptr to custom regs
  1320.      btst      #ADKB_UARTBRK&7,adkconr(a0)          ; were we breaking?
  1321.      beq.b      10$                      ; nope, skip reset
  1322.      ;
  1323.      move.w   #ADKF_UARTBRK,adkcon(a0)          ; stop breaking
  1324.      ;
  1325.      ;
  1326.      ;
  1327. 10$     move.b   Handshake(pc),d0              ; are we handshaking?
  1328.      beq.b      20$                      ; nope, generate interrupt
  1329.      btst      #CIAB_COMCTS,_ciabpra           ; clear to send?
  1330.      beq.b      20$                      ; yep, go start writing
  1331.      ;
  1332.      lea.l      timerReq(pc),a1              ; get ptr to timer request
  1333.      move.l   #1000,IOTV_TIME+TV_MICRO(a1)          ; wait for .001 seconds
  1334.      pea.l      30$(pc)                  ; branch to return
  1335.      jmp      _LVOSendIO(a6)              ; go queue it
  1336.      ;
  1337.      ;      CTS is clear so generate TBE interrupt to restart writing
  1338.      ;
  1339. 20$     move.w   #INTF_SETCLR|INTF_TBE,intreq(a0)    ; set TBE interrupt
  1340. 30$     rts                          ; return
  1341.      ;
  1342.      ;      Non serial interrupt
  1343.      ;
  1344.      cnop      0,4 ; align
  1345. level1n:
  1346.      movem.l  d0-d1/a0-a1/a5-a6,-(sp)          ; save registers
  1347.      lea      _custom,a0                  ; get ptr to custom regs
  1348.      move.w   intenar(a0),d1              ; get enabled interrupts
  1349.      and.w      intreqr(a0),d1              ; and in requested interrupts
  1350.      movea.l  SysBase(pc),a6              ; get ExecBase
  1351.      ;
  1352.      btst      #INTB_DSKBLK,d1              ; Disk block done?
  1353.      beq.b      10$                      ; nope, branch
  1354.      ;
  1355.      movem.l  IVDSKBLK(a6),a1/a5              ; get data and code ptrs
  1356.      pea.l      20$(pc)                  ; push return address
  1357.      jmp      (a5)                      ; jump to routine
  1358.      ;
  1359. 10$     btst      #INTB_SOFTINT,d1              ; software interrupt?
  1360.      beq.b      20$                      ; nope, branch
  1361.      ;
  1362.      movem.l  IVSOFTINT(a6),a1/a5              ; get data and code ptrs
  1363.      jsr      (a5)                      ; jump to routine
  1364.      ;
  1365. 20$     movem.l  (sp)+,d0-d1/a0-a1/a5-a6          ; restore registers
  1366.      rte                          ; return
  1367.      ;
  1368.      ;      Level 1 interrupt handler
  1369.      ;
  1370. level1:
  1371.      btst      #INTB_INTEN&7,_intenar          ; interrupts enabled?
  1372.      beq.b      35$                      ; nope, ignore
  1373.     IFEQ NEWCODE
  1374.      btst      #INTB_SOFTINT,_intreqr+1          ; software interrupt?
  1375.      bne.b      level1n                  ; nope, branch
  1376.     ENDC
  1377.      btst      #INTB_TBE,_intreqr+1              ; xmit buffer empty?
  1378.      beq.b      level1n                  ; nope, invoke old handler
  1379.      ;
  1380.      ;      Handle "Transmit Buffer Empty" interrupt (write)
  1381.      ;
  1382.      move.w   #INTF_TBE,_intreq              ; clear interrupt
  1383.      move.l   d0,-(sp)                  ; save D0 (faster than MOVEM)
  1384.      move.l   a0,-(sp)                  ; save A0 (faster than MOVEM)
  1385.      ;
  1386.      ;      If we're not handshaking, bypass it.
  1387.      ;
  1388. 10$     move.b   Handshake(pc),d0              ; are we handshaking?
  1389.      beq.b      20$                      ; nope, skip CTS test
  1390.      btst      #CIAB_COMCTS,_ciabpra           ; clear to send?
  1391.      bne.b      40$                      ; nope, branch
  1392.      ;
  1393.      ;      If cw_Length goes negative here, we are either done with a
  1394.      ;      request or we were called as a result of a fake interrupt
  1395.      ;      to force us to get the next request going.
  1396.      ;
  1397. 20$     subq.l   #1,cw_Length                  ; decr write length
  1398.      blt.b      60$                      ; < zero, done, branch
  1399.      ;
  1400.      ;      Currently processing a request.
  1401.      ;
  1402.      movea.l  cw_Buffer(pc),a0              ; get buffer ptr
  1403.      move.w   #256,d0                  ; set stop bit
  1404.      move.b   (a0)+,d0                  ; get next byte
  1405.      move.l   a0,cw_Buffer                  ; store buffer ptr
  1406.      move.w   d0,_serdat                  ; store in serdat reg
  1407.      ;
  1408. 30$     movea.l  (sp)+,a0                  ; restore registers
  1409.      move.l   (sp)+,d0                  ; restore registers
  1410. 35$     rte                          ; return
  1411.      ;
  1412.      ;      Queue a timer request to recheck CTS status
  1413.      ;
  1414. 40$     movem.l  d1/a1/a6,-(sp)              ; save registers
  1415.      lea.l      timerReq(pc),a1              ; get ptr to timer request
  1416.      move.l   #1000,IOTV_TIME+TV_MICRO(a1)          ; wait for .001 seconds
  1417.      movea.l  SysBase(pc),a6              ; get ExecBase
  1418.      jsr      _LVOSendIO(a6)              ; queue the request
  1419.      move.l   (sp)+,d1                  ; restore registers
  1420.      move.l   (sp)+,a1                  ; restore registers
  1421.      move.l   (sp)+,a6                  ; restore registers
  1422.      bra.b      30$                      ; go return
  1423.      ;
  1424.      ;      There aren't anymore requests, so clear and exit
  1425.      ;
  1426.      cnop      0,4 ; align
  1427. 50$     clr.l      cw_Length-Start(a6)              ; clear length
  1428.      clr.l      cw_IOReq-Start(a6)              ; clear
  1429.      move.l   (sp)+,d1                  ; restore registers
  1430.      move.l   (sp)+,a1                  ; restore registers
  1431.      move.l   (sp)+,a6                  ; restore registers
  1432.      bra.b      30$                      ; go return
  1433.      ;
  1434.      ;      Write request completed
  1435.      ;
  1436.      cnop      0,4 ; align
  1437. 60$     movem.l  d1/a1/a6,-(sp)              ; save registers
  1438.      ;
  1439.      move.l   cw_IOReq(pc),d0              ; active I/O request?
  1440.      beq.b      70$                      ; nope, branch
  1441.      ;
  1442.      ;      Reply it and setup for next
  1443.      ;
  1444.      movea.l  d0,a1                   ; get I/O request
  1445.      andi.b   #~(1<<IOSERB_ACTIVE),IO_FLAGS(a1)   ; no longer active
  1446.      clr.b      IO_ERROR(a1)                  ; no error
  1447.      movea.l  SysBase(pc),a6              ; get ExecBase
  1448.      DEBUGIO  replyIO
  1449.      jsr      _LVOReplyMsg(a6)              ; return I/O request
  1450.      ;
  1451. 70$     lea.l      Start(pc),a6                  ; get section base
  1452.      ;
  1453.      lea.l      writeQ(pc),a1               ; get ptr to write queue
  1454.      move.l   (a1),a0                  ; get head of list
  1455.      move.l   (a0),d0                  ; get successor
  1456.      beq.b      50$                      ; end of list? yep, branch
  1457.      ;
  1458.      ;      Remove the node from the list
  1459.      ;
  1460.      move.l   d0,(a1)                  ; make new head
  1461.      exg.l      d0,a0                   ; swap nodes
  1462.      move.l   a1,LN_PRED(a0)              ; store predecessor
  1463.      ;
  1464.      move.l   d0,a1                   ; get I/O request
  1465.      ;
  1466.      ;      If it's a BREAK, then branch to process as such.
  1467.      ;
  1468.      cmpi.w   #SDCMD_BREAK,IO_COMMAND(a1)          ; BREAK command?
  1469.      beq.b      100$                      ; yep, branch
  1470.      ;
  1471.      ;      Check for absolute length
  1472.      ;
  1473.      move.l   IO_DATA(a1),a0              ; get data ptr
  1474.      moveq      #-1,d1                  ; get value
  1475.      move.l   IO_LENGTH(a1),d0              ; get length
  1476.      cmp.l      d1,d0                   ; length = -1?
  1477.      bne.b      90$                      ; nope, skip scan
  1478.      ;
  1479.      ;      Scan the data for null to calc the length
  1480.      ;
  1481.      move.l   a0,d1                   ; save data ptr
  1482. 80$     tst.b      (a0)+                   ; does it equal 0? (first byte)
  1483.      beq.b      81$                      ; yep, finish
  1484.      tst.b      (a0)+                   ; does it equal 0? (second byte)
  1485.      beq.b      81$                      ; yep, finish
  1486.      tst.b      (a0)+                   ; does it equal 0? (third byte)
  1487.      beq.b      81$                      ; yep, finish
  1488.      tst.b      (a0)+                   ; does it equal 0? (fourth byte)
  1489.      bne.b      80$                      ; nope, loop
  1490. 81$
  1491.      suba.l   d1,a0                   ; calc # of bytes
  1492.      move.l   a0,d0                   ; xfer
  1493.      movea.l  d1,a0                   ; get data ptr
  1494.      ;
  1495. 90$     move.l   d0,IO_ACTUAL(a1)              ; go ahead and set it
  1496.      move.b   IO_FLAGS(a1),d1
  1497.      andi.b   #~(1<<IOSERB_QUEUED),d1          ; no longer queued
  1498.      ori.b      #1<<IOSERB_ACTIVE,d1              ; make it active
  1499.      move.b   d1,IO_FLAGS(a1)
  1500.      move.l   d0,cw_Length-Start(a6)          ; store length
  1501.      move.l   a0,cw_Buffer-Start(a6)          ; store buffer ptr
  1502.      move.l   a1,cw_IOReq-Start(a6)           ; store I/O request ptr
  1503.      ;
  1504.      move.l   (sp)+,d1                  ; restore registers
  1505.      move.l   (sp)+,a1                  ; restore registers
  1506.      move.l   (sp)+,a6                  ; restore registers
  1507.      bra      10$                      ; go start request
  1508.      ;
  1509.      ;      Start the BREAK.
  1510.      ;
  1511.      cnop      0,4 ; align
  1512. 100$     move.b   IO_FLAGS(a1),d1
  1513.      andi.b   #~(1<<IOSERB_QUEUED),d1          ; no longer queued
  1514.      ori.b      #1<<IOSERB_ACTIVE,d1              ; make it active
  1515.      move.b   d1,IO_FLAGS(a1)
  1516.      clr.l      cw_Length-Start(a6)              ; clear length
  1517.      move.l   a1,cw_IOReq-Start(a6)           ; store I/O request ptr
  1518.      move.w   #ADKF_SETCLR|ADKF_UARTBRK,_adkcon   ; start break
  1519.      move.l   IO_BRKTIME(a1),d0              ; get break time
  1520.      lea.l      timerReq(pc),a1              ; get ptr to timer request
  1521.      move.l   d0,IOTV_TIME+TV_MICRO(a1)          ; set the timeout
  1522.      movea.l  SysBase(pc),a6              ; get ExecBase
  1523.      jsr      _LVOSendIO(a6)              ; queue the request
  1524.      move.l   (sp)+,d1                  ; restore registers
  1525.      move.l   (sp)+,a1                  ; restore registers
  1526.      move.l   (sp)+,a6                  ; restore registers
  1527.      bra      30$                      ; go exit
  1528.      ;
  1529.      ;      Non serial interrupt
  1530.      ;
  1531.      cnop      0,4 ; align
  1532. level5n:
  1533.      movem.l  d0-d1/a0-a1/a5-a6,-(sp)          ; save registers
  1534.      lea      _custom,a0                  ; get ptr to custom regs
  1535.      move.w   intenar(a0),d1              ; get enabled interrupts
  1536.      and.w      intreqr(a0),d1              ; and in requested interrupts
  1537.      movea.l  SysBase(pc),a6              ; get ExecBase
  1538.      btst      #INTB_DSKSYNC,d1              ; Disk synchronized?
  1539.      beq.b      10$                      ; nope, branch
  1540.      movem.l  IVDSKSYNC(A6),a1/a5              ; get data and code ptrs
  1541.      jsr      (a5)                      ; branch to routine
  1542. 10$     movem.l  (sp)+,d0-d1/a0-a1/a5-a6          ; restore registers
  1543.      rte                          ; return
  1544.      ;
  1545.      ;      Default Level 5 handler
  1546.      ;
  1547. level5:
  1548.      btst      #INTB_INTEN&7,_intenar          ; interrupts enabled?
  1549.      beq.b      45$                      ; nope, ignore
  1550.      btst      #INTB_RBF&7,_intreqr              ; receive buffer full?
  1551.      beq.b      level5n                  ; nope, invoke old handler
  1552.      ;
  1553.      move.l   a0,-(sp)                  ; save registers
  1554.      move.l   a1,-(sp)                  ; save registers
  1555.      lea      _custom,a1                  ; get ptr to custom regs
  1556.      ;
  1557. 10$     tst.b      serdatr(a1)                  ; Overrun?
  1558.      bpl.b      20$                      ; nope, branch
  1559.      ;
  1560.      ;      We've missed some data, so set overrun flag.
  1561.      ;
  1562.      addq.b   #1,Overrun                  ; set overrun flag
  1563. 20$     movea.l  i_BufIn(pc),a0              ; get current ptr
  1564.      move.b   serdatr+1(a1),(a0)+              ; store received byte
  1565.      move.w   #INTF_RBF,intreq(a1)              ; clear RBF interrupt
  1566.      addq.l   #1,i_InCnt                  ; incr bytes in buffer
  1567.      ;
  1568.      cmpa.l   i_BufEnd(pc),a0              ; hit end of buffer?
  1569.      beq.b      60$                      ; yep, branch
  1570. 30$     move.l   a0,i_BufIn                  ; store input ptr
  1571.      ;
  1572.      subq.l   #1,i_Thresh                  ; close to full buffer?
  1573.      beq.b      70$                      ; yep, branch
  1574.      ;
  1575. 40$     btst      #INTB_RBF&7,intreqr(a1)          ; receive buffer full?
  1576.      bne.b      10$                      ; yep, go get another byte
  1577.      ;
  1578.      movea.l  (sp)+,a1                  ; restore registers
  1579.      movea.l  (sp)+,a0                  ; restore registers
  1580. 45$     rte                          ; return
  1581.      ;
  1582.      ;      Hit physical end of buffer, so wrap to the start of the buffer.
  1583.      ;
  1584. 60$     movea.l  i_BufPtr(pc),a0              ; get buffer ptr
  1585.      bra.b      30$                      ; continue
  1586.      ;
  1587.      ;      Hit buffer threshold, so tell other end not to send any more
  1588.      ;      data.
  1589.      ;
  1590.      cnop      0,4 ; align
  1591. 70$     tst.b      Handshake                  ; are we handshaking?
  1592.      beq.b      40$                      ; nope, skip RTS
  1593.      ori.b      #1<<CIAB_COMRTS,_ciabpra          ; block further input
  1594.      bra.b      40$                      ; go return
  1595.      ;
  1596.      ;
  1597.      ;
  1598.      cnop      0,4 ; align
  1599. level2:
  1600.      ;
  1601.      ;      If there's nothing in the buffer, there's no point in going
  1602.      ;      any further.
  1603.      ;
  1604.      move.l   i_InCnt(pc),d0              ; anything in the buffer?
  1605.      bne.b      20$                      ; yep, branch
  1606. 10$     moveq      #0,d0                   ; set Z flag
  1607.      rts                          ; return
  1608.      ;
  1609.      ;      If we've been "disabled" then get out.
  1610.      ;
  1611.      cnop      0,4 ; align
  1612. 20$     move.b   disableRead(pc),d0              ; internally disabled?
  1613.      bge.b      10$                      ; yep, get out of here
  1614.      lea.l      Start(pc),a5                  ; get base
  1615.      ;
  1616.      ;      If we have an active request, branch down and try to fulfill it.
  1617.      ;
  1618.      move.l   cr_IOReq(pc),d0              ; get and test active I/O
  1619.      bne.b      30$                      ; nzero, active, branch
  1620.      ;
  1621.      ;      Get first node in list and test if empty.
  1622.      ;
  1623.      move.l   (a1),a0                  ; get head of list
  1624.      move.l   (a0),d0                  ; get successor
  1625.      beq.b      10$                      ; end of list? yep, branch
  1626.      ;
  1627.      ;      Remove the node from the list
  1628.      ;
  1629.      move.l   d0,(a1)                  ; make new head
  1630.      exg.l      d0,a0                   ; swap nodes
  1631.      move.l   a1,LN_PRED(a0)              ; store predecessor
  1632.      ;
  1633.      ;      Setup fields for processing a read request
  1634.      ;
  1635.      movea.l  d0,a1                   ; get I/O request
  1636.      move.b   IO_FLAGS(a1),d1
  1637.      andi.b   #~(1<<IOSERB_QUEUED),d1          ; no longer queued
  1638.      ori.b      #1<<IOSERB_ACTIVE,d1              ; make it active
  1639.      move.b   d1,IO_FLAGS(a1)
  1640.      move.l   a1,cr_IOReq-Start(a5)           ; store I/O request
  1641.      move.l   IO_DATA(a1),cr_OutPtr-Start(a5)     ; get/set output ptr
  1642.      move.l   IO_LENGTH(a1),cr_Length-Start(a5)   ; get/set output count
  1643.      ;
  1644.      ;      Process an active I/O request
  1645.      ;
  1646. 30$     movea.l  SysBase(pc),a6              ; get ExecBase
  1647.      move.l   d0,a1                   ; get I/O request
  1648.      bsr.b      copyData                  ; go copy 'em
  1649.      tst.l      d0                      ; done with request?
  1650.      beq.b      10$                      ; nope, branch
  1651.      ;
  1652.      ;      the request has been satisfied, so return it.
  1653.      ;
  1654.      clr.l      cr_IOReq-Start(a5)              ; clear request
  1655.      andi.b   #~(1<<IOSERB_ACTIVE),IO_FLAGS(a1)   ; no longer active
  1656.      DEBUGIO  replyIO
  1657.      pea.l      10$(pc)
  1658.      jmp      _LVOReplyMsg(a6)              ; return I/O
  1659.      ;
  1660.      ;      Registers:
  1661.      ;      Entry:   A1        Ptr to I/O Request
  1662.      ;           A6        ExecBase
  1663.      ;      Exit:    D0        ZERO - request not done, do not reply it
  1664.      ;                NZERO - request done, reply it
  1665.      ;
  1666. copyData:
  1667.      ;
  1668.      ;      Process an active I/O request (or fall through from above)
  1669.      ;
  1670.      movem.l  d2-d5/a1-a5,-(sp)              ; save registers
  1671.      lea.l      Start(pc),a5                  ; get base
  1672.      movea.l  a1,a4                   ; get I/O request
  1673.      ;
  1674.      movea.l  i_BufOut(pc),a2              ; get current bufout ptr
  1675.      movea.l  cr_OutPtr(pc),a3              ; get current output ptr
  1676.      move.l   cr_Length(pc),d2              ; get current bytes needed
  1677.      move.l   i_InCnt(pc),d3              ; get current bytes in buffer
  1678.      ;
  1679.      ;      If we don't have enough bytes to satisfy the request,
  1680.      ;      set the length to the number of bytes we do have.
  1681.      ;
  1682.      cmp.l      d2,d3                   ; enuf to satisfy request?
  1683.      bge.b      15$                      ; yep, so branch
  1684.      move.l   d3,d2                   ; # to copy = # in buffer
  1685.      bra.b      15$                      ; branch to loop entry
  1686.      ;
  1687.      ;      Start of copy loop.
  1688.      ;
  1689.      cnop      0,4 ; align
  1690. 10$     movea.l  i_BufPtr(pc),a2              ; reset bufout to start
  1691.      ;
  1692.      ;      Entry point of copy loop.
  1693.      ;
  1694. 15$     move.l   d2,d3                   ; xfer # of bytes to copy
  1695.      ;
  1696.      ;      If the copy will extend past the end of the buffer, we can
  1697.      ;      only copy the number of bytes to the end this go around.
  1698.      ;
  1699.      move.l   i_BufEnd(pc),d0              ; get ptr to end of buf
  1700.      sub.l      a2,d0                   ; calc # of bytes to end
  1701.      cmp.l      d0,d3                   ; # to copy < # to end?
  1702.      blt.b      20$                      ; yep, branch
  1703.      move.l   d0,d3                   ; get bytes to end
  1704.      ;
  1705.      ;      Registers:
  1706.      ;
  1707.      ;      A2 = pointer from which data will be copied
  1708.      ;      A3 = pointer to which data will be copied
  1709.      ;      D2 = number of bytes that need to be copied
  1710.      ;      D3 = number of bytes to copy this iteration
  1711.      ;
  1712. 20$     btst      #SERB_EOFMODE,IO_SERFLAGS(a4)       ; EOFMODE requested?
  1713.      beq.b      30$                      ; nope, just go copy
  1714.      ;
  1715.      ;      EOFMODE was specified so copy characters 1 at a time until
  1716.      ;      we hit an EOF character, the output butter has filled, or
  1717.      ;      the input buffer has drained.
  1718.      ;
  1719.      move.l   d3,d0                   ; get length
  1720.      ;
  1721.      lea.l      IO_TERMARRAY+7(a4),a1           ; get termarry ptr
  1722. 21$     move.b   (a2)+,d1                  ; get byte
  1723.      ; This way the term char IS copied (if the term char is not copied eofmode will fail)
  1724.      move.b   d1,(a3)+                  ; put in output buffer
  1725.      ;
  1726.      suba.w   #7,a1
  1727.      cmp.b      (a1)+,d1                  ; found term char?
  1728.      bge.b      22$                      ; possibly, branch
  1729.      cmp.b      (a1)+,d1                  ; found term char?
  1730.      bge.b      22$                      ; possibly, branch
  1731.      cmp.b      (a1)+,d1                  ; found term char?
  1732.      bge.b      22$                      ; possibly, branch
  1733.      cmp.b      (a1)+,d1                  ; found term char?
  1734.      bge.b      22$                      ; possibly, branch
  1735.      cmp.b      (a1)+,d1                  ; found term char?
  1736.      bge.b      22$                      ; possibly, branch
  1737.      cmp.b      (a1)+,d1                  ; found term char?
  1738.      bge.b      22$                      ; possibly, branch
  1739.      cmp.b      (a1)+,d1                  ; found term char?
  1740.      bge.b      22$                      ; possibly, branch
  1741.      cmp.b      (a1),d1                  ; found term char?
  1742.      bgt.b      23$                      ; nope, branch
  1743. 22$     beq.b      24$                      ; term char found?
  1744.      ;
  1745.      ;      Didn't find a term character, so continue with the copy loop
  1746.      ;
  1747. 23$
  1748.      subq.l   #1,d0                   ; decr length counter
  1749.      bne.b      21$                      ; continue if more
  1750.      bra.b      40$                      ; done with copy, branch
  1751.      ;
  1752.      ;      We've found a termination character.
  1753.      ;
  1754.      cnop      0,4 ; align
  1755. 24$     clr.l      cr_Length-Start(a5)              ; done with request
  1756.      bra.b      50$                      ; branch
  1757.      ;
  1758.      ;      EOFMODE not specified, so just do a bulk copy.
  1759.      ;
  1760.      ;      XXX POSSIBLE SPEEDUP XXX
  1761.      ;
  1762.      ;      For short copies it would be quicker to have a simple inline
  1763.      ;      loop, but what's short???  It would be different by CPU.
  1764.      ;
  1765.      cnop      0,4 ; align
  1766. 30$
  1767.      move.l   d3,d0                   ; get length
  1768.      movea.l  a3,a1                   ; where to put it
  1769.      movea.l  a2,a0                   ; where to get it
  1770. ; NB: buffer size is multiple of 64bytes (not contents size)
  1771.      jsr      _LVOCopyMem(a6)              ; copy it
  1772.      adda.l   d3,a2                   ; update bufout
  1773.      adda.l   d3,a3                   ; update outptr
  1774.      ;
  1775.      ;      Fall through and entered from EOFMODE loop
  1776.      ;
  1777.      ;      If the following calculation results in a value greater than
  1778.      ;      zero, then we have a buffer wrap and need to process the
  1779.      ;      remaining bytes at the beginning of the buffer.
  1780.      ;
  1781. 40$     sub.l      d3,d2                   ; calc bytes left to copy
  1782.      bgt      10$                      ; >0, more to copy, branch
  1783.      ;
  1784.      ;
  1785.      ;
  1786. 50$     move.l   a3,d1                   ; get outptr
  1787.      sub.l      cr_OutPtr(pc),d1              ; calc length
  1788.      move.l   a3,cr_OutPtr-Start(a5)          ; update outptr
  1789.      ;
  1790.      ;      Update output ptr and I/O request
  1791.      ;
  1792.      move.l   a2,i_BufOut-Start(a5)           ; store bufout ptr
  1793.      add.l      d1,IO_ACTUAL(a4)              ; update I/O request
  1794.      ;
  1795.      ;      Update number of bytes left in the buffer.
  1796.      ;
  1797.      sub.l      d1,i_InCnt-Start(a5)              ; calc bytes left in buffer
  1798.      ;
  1799.      ;      If the threshold becomes positive here, then, if requested,
  1800.      ;      tell the other end that it's okay to start sending more data.
  1801.      ;
  1802.      add.l      d1,i_Thresh-Start(a5)           ; calc thresh and test
  1803.      ble.b      60$                      ; <= 0, need more data, skip
  1804.      tst.b      Handshake-Start(a5)              ; are we handshaking?
  1805.      beq.b      60$                      ; nope, skip RTS
  1806.      andi.b   #~(1<<CIAB_COMRTS),_ciabpra          ; ready to receive more data
  1807.      ;
  1808.      ;      Set error if we've had any overruns.
  1809.      ;
  1810. 60$     tst.b      Overrun-Start(a5)              ; did overrun occur?
  1811.      beq.b      70$                      ; nope, branch
  1812.      clr.b      Overrun-Start(a5)              ; reset overrun flag
  1813.      move.b   #SerErr_LineErr,IO_ERROR(a4)          ; set error code
  1814.      ;
  1815.      ;      Calc number of bytes left to copy.  If the result is greater
  1816.      ;      than zero, then we have more to copy so return an incomplete
  1817.      ;      status.
  1818.      ;
  1819. 70$     moveq      #0,d0                   ; assume I/O incomplete
  1820.      sub.l      d1,cr_Length-Start(a5)          ; update length and test
  1821.      bgt.b      90$                      ; >0, more to do, branch
  1822.      ;
  1823.      ;      We've completed the I/O request either by copying the requested
  1824.      ;      of bytes or by finding an EOFMODE character, so return a "reply"
  1825.      ;      status.
  1826.      ;
  1827.      moveq      #1,d0                   ; indicate reply
  1828.      ;
  1829.      ;      Restore and exit
  1830.      ;
  1831. 90$     movem.l  (sp)+,d2-d5/a1-a5              ; restore registers
  1832.      rts                          ; return (status in D0)
  1833.      ;
  1834.      ;      Align data
  1835.      ;
  1836.      CNOP      0,4
  1837.      ;
  1838.      ;
  1839.      ;
  1840. Init:
  1841.      DC.L      sizeof_Base8n1
  1842.      DC.L      funcTab
  1843.      DC.L      dataTab
  1844.      DC.L      InitRoutine
  1845.      ;
  1846.      ;
  1847.      ;
  1848. funcTab:
  1849.      DC.W      -1
  1850.      DC.W      dev_Open-funcTab
  1851.      DC.W      dev_Close-funcTab
  1852.      DC.W      dev_Expunge-funcTab
  1853.      DC.W      dev_Null-funcTab
  1854.      DC.W      dev_BeginIO-funcTab
  1855.      DC.W      dev_AbortIO-funcTab
  1856.      DC.W      -1
  1857.      ;
  1858.      ;
  1859.      ;
  1860. dataTab:
  1861.      INITBYTE LN_TYPE,NT_DEVICE
  1862.      INITLONG LN_NAME,Name
  1863.      INITBYTE LIB_FLAGS,LIBF_SUMUSED|LIBF_CHANGED
  1864.      INITWORD LIB_VERSION,VERSION
  1865.      INITWORD LIB_REVISION,REVISION
  1866.      INITLONG LIB_IDSTRING,IdString
  1867.      DC.W      0
  1868.      ;
  1869.      ;      String Constants
  1870.      ;
  1871. miscresource:
  1872.      DC.B      "misc.resource",0
  1873. timerdevice:
  1874.      DC.B      "timer.device",0
  1875. intuitlib:
  1876.      DC.B      "intuition.library",0
  1877. Name:
  1878.      DC.B      "8n1.device",0
  1879. IdString:
  1880.      VSTRING
  1881.      ;
  1882.      ;      End of checksummed area.  (Realigns data too!)
  1883.      ;
  1884. ENDTag:
  1885.      CNOP      0,4
  1886.      ;
  1887.      ;      Global SysBase (Use instead of AbsExecBase for speed)
  1888.      ;
  1889. SysBase:
  1890.      DC.L      0
  1891.      ;
  1892.      ;      Internal buffer tracking (DO NOT CHANGE THE ORDER!!!!)
  1893.      ;
  1894. i_BufPtr:
  1895.      DC.L      0
  1896. i_BufIn:
  1897.      DC.L      0
  1898. i_BufOut:
  1899.      DC.L      0
  1900. i_BufEnd:
  1901.      DC.L      0
  1902. i_InCnt:
  1903.      DC.L      0
  1904. i_Thresh:
  1905.      DC.L      0
  1906.      ;
  1907.      ;      Used while processing a read request.
  1908.      ;
  1909. cr_IOReq:
  1910.      DC.L      0
  1911. cr_OutPtr:
  1912.      DC.L      0
  1913. cr_Length:
  1914.      DC.L      0
  1915.      ;
  1916.      ;      List head for read requests
  1917.      ;
  1918. readQ:
  1919.      DC.L      readQ+MLH_TAIL
  1920.      DC.L      0
  1921.      DC.L      readQ
  1922.      ;
  1923.      ;      Write control.
  1924.      ;
  1925. cw_Length:
  1926.      DC.L      0
  1927. cw_Buffer:
  1928.      DC.L      0
  1929. cw_IOReq:
  1930.      DC.L      0
  1931.      ;
  1932.      ;      List head for write requests
  1933.      ;
  1934. writeQ:
  1935.      DC.L      writeQ+MLH_TAIL
  1936.      DC.L      0
  1937.      DC.L      writeQ
  1938.      ;
  1939.      ;
  1940.      ;
  1941. timerPort:
  1942.      DC.L      0                      ; LN_SUCC
  1943.      DC.L      0                      ; LN_PRED
  1944.      DC.B      NT_MSGPORT                  ; LN_TYPE
  1945.      DC.B      0                      ; LN_PRI
  1946.      DC.L      0                      ; LN_NAME
  1947.      DC.B      3                      ; MP_FLAGS (undoc'ed)
  1948.      DC.B      0                      ; MP_SIGBIT
  1949.      DC.L      timerRtn                  ; MP_SIGTASK
  1950.      DC.L      timerPort+MP_MSGLIST+LH_TAIL          ; LH_HEAD
  1951.      DC.L      0                      ; LH_TAIL
  1952.      DC.L      timerPort+MP_MSGLIST              ; LH_TAILPRED
  1953.      DC.B      0                      ; LH_TYPE
  1954.      DC.B      0                      ; LH_pad
  1955.      DC.W      0                      ; long align
  1956.      ;
  1957.      ;
  1958.      ;
  1959. timerReq:
  1960.      DC.L      0                      ; LN_SUCC
  1961.      DC.L      0                      ; LN_PRED
  1962.      DC.B      NT_MESSAGE                  ; LN_TYPE
  1963.      DC.B      0                      ; LN_PRI
  1964.      DC.L      0                      ; LN_NAME
  1965.      DC.L      timerPort                  ; MN_REPLYPORT
  1966.      DC.W      IOTV_SIZE                  ; MN_LENGTH
  1967.      DC.L      0                      ; IO_DEVICE
  1968.      DC.L      0                      ; IO_UNIT
  1969.      DC.W      TR_ADDREQUEST               ; IO_COMMAND
  1970.      DC.B      0                      ; IO_FLAGS
  1971.      DC.B      0                      ; IO_ERROR
  1972.      DC.L      0                      ; TV_SECS
  1973.      DC.L      0                      ; TV_MICROS
  1974.      ;
  1975.      ;
  1976.      ;
  1977. VBInterrupt:
  1978.      DC.L      0                      ; LN_SUCC
  1979.      DC.L      0                      ; LN_PRED
  1980.      DC.B      NT_INTERRUPT                  ; LN_TYPE
  1981.      DC.B      0                      ; LN_PRI
  1982.      DC.L      Name                      ; LN_NAME
  1983.      DC.L      readQ                   ; IS_DATA
  1984.      DC.L      level2                  ; IS_CODE
  1985.      ;
  1986.      ;      Global flags
  1987.      ;
  1988. Overrun:
  1989.      DC.B      0
  1990. Handshake:
  1991.      DC.B      1
  1992. disableRead:
  1993.      DC.B      -1
  1994.      CNOP      0,4
  1995. cmdlist:
  1996.      dc.w      CMD_RESET
  1997.      dc.w      CMD_READ
  1998.      dc.w      CMD_WRITE
  1999.      dc.w      CMD_CLEAR
  2000.      dc.w      CMD_FLUSH
  2001.      dc.w      SDCMD_QUERY
  2002.      dc.w      SDCMD_BREAK
  2003.      dc.w      SDCMD_SETPARAMS
  2004.      dc.w      NSCMD_DEVICEQUERY
  2005.      dc.w      0
  2006.      ;
  2007.      ;
  2008.      ;
  2009.      END
  2010.  
  2011.